package com.example.activiti.component;

import com.example.activiti.goback.JumpAnyWhereCmd;
import com.example.activiti.po.ProcessNode;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.TaskServiceImpl;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
public class ProcessUtils {
	
	private static Logger log = LoggerFactory.getLogger(ProcessUtils.class);

    @Autowired
    TaskService taskService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    HistoryService historyService;

    public  void getIncomeNodesRecur(String currentNodeId, String processDefId, List<ProcessNode> incomeNodes, boolean isAll) {
        getIncomeNodesRecur(currentNodeId, processDefId, incomeNodes, isAll, true, null);
    }

    public void getIncomeNodesRecur(String currentNodeId, String processDefId, List<ProcessNode> incomeNodes, boolean isAll, String originalCurrentNodeId) {
        getIncomeNodesRecur(currentNodeId, processDefId, incomeNodes, isAll, true, originalCurrentNodeId);
    }

    /**
     * 根据流程定义id获取流程实例
     * @param processDefId
     * @return
     */
    public Process getProcess(String processDefId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
        return bpmnModel.getProcesses().get(0);
    }
    public  void getIncomeNodesRecur(String currentNodeId, String processDefId, List<ProcessNode> incomeNodes, boolean isAll, boolean isFirstExec, String originalCurrentNodeId) {
        Process process = getProcess(processDefId);
        if (!isFirstExec) {
            if (currentNodeId.equals(originalCurrentNodeId)) {
                return;
            }
        }
        FlowElement currentFlowElement = process.getFlowElement(currentNodeId,true);
        FlowElementsContainer pec = currentFlowElement.getParentContainer();

        List<SequenceFlow> incomingFlows = null;
        if (currentFlowElement instanceof UserTask) {
            incomingFlows = ((UserTask) currentFlowElement).getIncomingFlows();
        } else if (currentFlowElement instanceof Gateway) {
            incomingFlows = ((Gateway) currentFlowElement).getIncomingFlows();
        } else if (currentFlowElement instanceof StartEvent) {
            incomingFlows = ((StartEvent) currentFlowElement).getIncomingFlows();
        }
        if (incomingFlows != null && incomingFlows.size() > 0) {
            incomingFlows.forEach(incomingFlow -> {
//	                String expression = incomingFlow.getConditionExpression();
                // 出线的上一节点
                String sourceFlowElementID = incomingFlow.getSourceRef();
                // 查询上一节点的信息
                FlowElement preFlowElement = process.getFlowElement(sourceFlowElementID,true);

                //用户任务
                if (preFlowElement instanceof UserTask) {
//                    preFlowElement.get
                    incomeNodes.add(new ProcessNode(preFlowElement.getId(), preFlowElement.getName()));
                    if (isAll) {
                        getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, true, false, originalCurrentNodeId);
                    }
                }

                if(preFlowElement instanceof SubProcess) {
                    incomeNodes.add(new ProcessNode(preFlowElement.getId(), preFlowElement.getName()));
                    log.info("获取最后节点id={},name={}",preFlowElement.getId(),preFlowElement.getName());

                }
                if(preFlowElement instanceof StartEvent) {
                    getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, isAll, false, originalCurrentNodeId);
                }

                //排他网关
                else if (preFlowElement instanceof ExclusiveGateway) {
                    getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, isAll, false, originalCurrentNodeId);
                }
                //并行网关
                else if (preFlowElement instanceof ParallelGateway) {
                    getIncomeNodesRecur(preFlowElement.getId(), processDefId, incomeNodes, isAll, false, originalCurrentNodeId);
                }
            });
        }
    }

    /**
     * 获取上一环节节点信息
     * @param currentNodeId 当前节点ID
     * @param processDefId 流程定义ID
     * @return ProcessNode
     */
    public ProcessNode getPreOneIncomeNode(String currentNodeId, String processDefId) {
        final List<ProcessNode> preNodes = new ArrayList<>();
        getIncomeNodesRecur(currentNodeId, processDefId, preNodes, false);
        for (int i = 0; i < preNodes.size(); i++) {
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                    .processDefinitionId(processDefId).activityId(preNodes.get(i).getId()).finished().list();
            if (historicActivityInstances==null||historicActivityInstances.isEmpty()) {
                preNodes.remove(i);
                i--;
            }
        }
        if (preNodes==null||preNodes.isEmpty()) {
            return null;
        }
        return preNodes.get(0);
    }

    /**
     * 流程回退
     * @param taskId 当前操作节点
     * @param comment 回退批注
     * @param userId 当前操作人
     */
    public void goBack(String taskId,String comment,String userId) {
        Optional<Task> optTask = Optional.ofNullable(taskService.createTaskQuery().taskId(taskId).singleResult());
        if(!optTask.isPresent()) {
            throw new RuntimeException("根据"+taskId+"查询不到节点");
        }
        Task curTask = optTask.get();
        String processDefinitionId = curTask.getProcessDefinitionId();

        String curActivityId = runtimeService.createExecutionQuery().executionId(curTask.getExecutionId())
                .singleResult().getActivityId();
        //获取上一节点
        ProcessNode pn = getPreOneIncomeNode(curActivityId, processDefinitionId);

        log.debug("上一节点{}",pn);


        if(pn==null) {
            throw new RuntimeException("没有上一节点，无法回退");
        }
        //设置非直接结束
        taskService.setVariable(taskId, "directEnd", 0);
        taskService.setVariable(taskId, "isBack", 1);

        Map<String,Object> variables = taskService.getVariables(taskId);

        variables.put("directEnd",0);
        variables.put("isBack",1);

        taskService.removeVariables(taskId,variables.keySet());

        nodeJumpTo(taskId, pn.getId(), userId+"", variables, comment);


    }

    /**
     * 节点跳转
     * @param taskId 当前任务ID
     * @param targetNodeId 目标节点定义ID
     * @param assignee 审批用户
     * @param variables 流转数据
     * @param comment 备注/意见
     */
    public void nodeJumpTo(String taskId, String targetNodeId, String assignee, Map<String, Object> variables, String comment) {
        log.info("开始跳转");
        CommandExecutor commandExecutor = ((TaskServiceImpl) taskService).getCommandExecutor();
        commandExecutor.execute(new JumpAnyWhereCmd(taskId, targetNodeId, assignee, variables, comment));
    }

}
